#include "toralize.h"

/*
supported platform: linux

1.make

2.touch /usr/bin/toralize
------------------
#!/bin/bash
export LD_PRELOAD=/your/so/location/toralize.so
${@}
unset LD_PRELOAD
------------------

3.use `toralize <command>`, e.g. `toralize curl -v http://46.227.66.141/`

 */

Req *request(const struct sockaddr_in *sock) {
    Req *req;
    req = malloc(reqsize);
    req->vn = 4;
    req->cd = 1;
    req->dstport = sock->sin_port;
    req->dstip = sock->sin_addr.s_addr;
    strncpy((char *) req->userid, USERNAME, 8);
    return req;
}

/**
 *  在自定义的动态库中定义与系统调用 connect(..) 相同签名的函数，用来代理 connect 系统调用
 *  内容：添加一个 sock4 连接层，用来连接 tor 网络
 */
int connect(int s2, const struct sockaddr *sock2, socklen_t addr_len) {

    int (*p)(int, const struct sockaddr *, socklen_t);
    //get address of a symbol
    p = dlsym(RTLD_NEXT, "connect");

    // 1.prepare for connecting to proxy
    int s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0) {
        perror("fail to call socket()");
        return -1;
    }
    struct sockaddr_in sock;
    sock.sin_family = AF_INET;
    sock.sin_port = htons(PROXY_PORT);
    sock.sin_addr.s_addr = inet_addr(PROXY);
    // connect to proxy
    if (p(s, (struct sockaddr *) &sock, sizeof(sock))) {
        perror("fail to connect proxy server");
        return -1;
    }
    printf("connect to proxy server successfully!\n");

    // 2.write socks4 request packet
    Req *req = request((struct sockaddr_in *) sock2);
    write(s, req, reqsize);

    // 3.read sock4 response packet
    char buf[ressize];
    memset(buf, 0, ressize);
    if (read(s, buf, ressize) < 1) {
        perror("fail to read.\n");
        free(req);
        close(s);
        return -1;
    }

    // 4.check socks4 request result
    Res *res = (Res *) buf;
    if (res->cd != 90) {
        fprintf(stderr, "unable to traverse the proxy, error code(cd) is %d.\n", res->cd);
        free(req);
        close(s);
        return -1;
    }
    printf("connect through the proxy.\n");

    // 5.duplicate between sockets
    dup2(s, s2);
    free(req);
    return 0;
}
